/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package de.swta.freezay.database.controller;

import de.swta.freezay.database.controller.exceptions.NonexistentEntityException;
import de.swta.freezay.database.controller.exceptions.PreexistingEntityException;
import de.swta.freezay.database.dbEntities.Category;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import de.swta.freezay.database.dbEntities.Package;
import java.util.ArrayList;
import java.util.List;
import de.swta.freezay.database.dbEntities.Item;

/**
 *
 * @author Christian
 */
public class CategoryJpaController {

    public CategoryJpaController() {
        emf = Persistence.createEntityManagerFactory("FreezayPU");
    }
    private EntityManagerFactory emf = null;

    public List<Category> findCategoryEntities(int maxResults, int firstResult,
            String sortBy, boolean ascending) {
        
        EntityManager em = getEntityManager();
        try {
            Query q = em.createQuery("select object(o) from Category as o order "
                    + "by o." + sortBy + " " + (ascending ? "ASC" : "DESC"));

            q.setMaxResults(maxResults);
            q.setFirstResult(firstResult);

            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Category category) throws PreexistingEntityException, Exception {
        if (category.getPackageCollection() == null) {
            category.setPackageCollection(new ArrayList<Package>());
        }
        if (category.getItemCollection() == null) {
            category.setItemCollection(new ArrayList<Item>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            List<Package> attachedPackageCollection = new ArrayList<Package>();
            for (Package packageCollectionPackageToAttach : category.getPackageCollection()) {
                packageCollectionPackageToAttach = em.getReference(packageCollectionPackageToAttach.getClass(), packageCollectionPackageToAttach.getId());
                attachedPackageCollection.add(packageCollectionPackageToAttach);
            }
            category.setPackageCollection(attachedPackageCollection);
            List<Item> attachedItemCollection = new ArrayList<Item>();
            for (Item itemCollectionItemToAttach : category.getItemCollection()) {
                itemCollectionItemToAttach = em.getReference(itemCollectionItemToAttach.getClass(), itemCollectionItemToAttach.getId());
                attachedItemCollection.add(itemCollectionItemToAttach);
            }
            category.setItemCollection(attachedItemCollection);
            em.persist(category);
            for (Package packageCollectionPackage : category.getPackageCollection()) {
                Category oldCategoryOfPackageCollectionPackage = packageCollectionPackage.getCategory();
                packageCollectionPackage.setCategory(category);
                packageCollectionPackage = em.merge(packageCollectionPackage);
                if (oldCategoryOfPackageCollectionPackage != null) {
                    oldCategoryOfPackageCollectionPackage.getPackageCollection().remove(packageCollectionPackage);
                    oldCategoryOfPackageCollectionPackage = em.merge(oldCategoryOfPackageCollectionPackage);
                }
            }
            for (Item itemCollectionItem : category.getItemCollection()) {
                Category oldCategoryOfItemCollectionItem = itemCollectionItem.getCategory();
                itemCollectionItem.setCategory(category);
                itemCollectionItem = em.merge(itemCollectionItem);
                if (oldCategoryOfItemCollectionItem != null) {
                    oldCategoryOfItemCollectionItem.getItemCollection().remove(itemCollectionItem);
                    oldCategoryOfItemCollectionItem = em.merge(oldCategoryOfItemCollectionItem);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findCategory(category.getId()) != null) {
                throw new PreexistingEntityException("Category " + category + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Category category) throws NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Category persistentCategory = em.find(Category.class, category.getId());
            List<Package> packageCollectionOld = persistentCategory.getPackageCollection();
            List<Package> packageCollectionNew = category.getPackageCollection();
            List<Item> itemCollectionOld = persistentCategory.getItemCollection();
            List<Item> itemCollectionNew = category.getItemCollection();
            List<Package> attachedPackageCollectionNew = new ArrayList<Package>();
            for (Package packageCollectionNewPackageToAttach : packageCollectionNew) {
                packageCollectionNewPackageToAttach = em.getReference(packageCollectionNewPackageToAttach.getClass(), packageCollectionNewPackageToAttach.getId());
                attachedPackageCollectionNew.add(packageCollectionNewPackageToAttach);
            }
            packageCollectionNew = attachedPackageCollectionNew;
            category.setPackageCollection(packageCollectionNew);
            List<Item> attachedItemCollectionNew = new ArrayList<Item>();
            for (Item itemCollectionNewItemToAttach : itemCollectionNew) {
                itemCollectionNewItemToAttach = em.getReference(itemCollectionNewItemToAttach.getClass(), itemCollectionNewItemToAttach.getId());
                attachedItemCollectionNew.add(itemCollectionNewItemToAttach);
            }
            itemCollectionNew = attachedItemCollectionNew;
            category.setItemCollection(itemCollectionNew);
            category = em.merge(category);
            for (Package packageCollectionOldPackage : packageCollectionOld) {
                if (!packageCollectionNew.contains(packageCollectionOldPackage)) {
                    packageCollectionOldPackage.setCategory(null);
                    packageCollectionOldPackage = em.merge(packageCollectionOldPackage);
                }
            }
            for (Package packageCollectionNewPackage : packageCollectionNew) {
                if (!packageCollectionOld.contains(packageCollectionNewPackage)) {
                    Category oldCategoryOfPackageCollectionNewPackage = packageCollectionNewPackage.getCategory();
                    packageCollectionNewPackage.setCategory(category);
                    packageCollectionNewPackage = em.merge(packageCollectionNewPackage);
                    if (oldCategoryOfPackageCollectionNewPackage != null && !oldCategoryOfPackageCollectionNewPackage.equals(category)) {
                        oldCategoryOfPackageCollectionNewPackage.getPackageCollection().remove(packageCollectionNewPackage);
                        oldCategoryOfPackageCollectionNewPackage = em.merge(oldCategoryOfPackageCollectionNewPackage);
                    }
                }
            }
            for (Item itemCollectionOldItem : itemCollectionOld) {
                if (!itemCollectionNew.contains(itemCollectionOldItem)) {
                    itemCollectionOldItem.setCategory(null);
                    itemCollectionOldItem = em.merge(itemCollectionOldItem);
                }
            }
            for (Item itemCollectionNewItem : itemCollectionNew) {
                if (!itemCollectionOld.contains(itemCollectionNewItem)) {
                    Category oldCategoryOfItemCollectionNewItem = itemCollectionNewItem.getCategory();
                    itemCollectionNewItem.setCategory(category);
                    itemCollectionNewItem = em.merge(itemCollectionNewItem);
                    if (oldCategoryOfItemCollectionNewItem != null && !oldCategoryOfItemCollectionNewItem.equals(category)) {
                        oldCategoryOfItemCollectionNewItem.getItemCollection().remove(itemCollectionNewItem);
                        oldCategoryOfItemCollectionNewItem = em.merge(oldCategoryOfItemCollectionNewItem);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Integer id = category.getId();
                if (findCategory(id) == null) {
                    throw new NonexistentEntityException("The category with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(Integer id) throws NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Category category;
            try {
                category = em.getReference(Category.class, id);
                category.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The category with id " + id + " no longer exists.", enfe);
            }
            List<Package> packageCollection = category.getPackageCollection();
            for (Package packageCollectionPackage : packageCollection) {
                packageCollectionPackage.setCategory(null);
                packageCollectionPackage = em.merge(packageCollectionPackage);
            }
            List<Item> itemCollection = category.getItemCollection();
            for (Item itemCollectionItem : itemCollection) {
                itemCollectionItem.setCategory(null);
                itemCollectionItem = em.merge(itemCollectionItem);
            }
            em.remove(category);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public boolean isUsed(Integer id) {
        boolean isUsed = false;

        Category catToTest = this.findCategory(id);

        if (catToTest != null) {
            isUsed = (catToTest.getItemCollection().size() != 0
                    || catToTest.getPackageCollection().size() != 0);
        }

        return isUsed;
    }
    
    public List<Category> findCategoryEntities() {
        return findCategoryEntities(true, -1, -1);
    }

    public List<Category> findCategoryEntities(int maxResults, int firstResult) {
        return findCategoryEntities(false, maxResults, firstResult);
    }

    private List<Category> findCategoryEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            Query q = em.createQuery("select object(o) from Category as o");
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Category findCategory(Integer id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Category.class, id);
        } finally {
            em.close();
        }
    }

    public int getCategoryCount() {
        EntityManager em = getEntityManager();
        try {
            return ((Long) em.createQuery("select count(o) from Category as o").getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }

    public List<String> getCategoryNames() {
        List<Category> cats = this.findCategoryEntities();
        List<String> catNames = new ArrayList<String>();

        for (int i = 0; i < cats.size(); i++) {
            catNames.add(cats.get(i).getName());
        }

        return catNames;
    }
}
